package com.pillar;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import net.bytebuddy.utility.RandomString;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 基于websocket的netty客户端
 *
 */
public class ClientByNetty {

    public static void main(String[] args) throws Exception {
        for (int i = 0; i < 200; i++) {

            startClient(UUID.randomUUID().toString());
        }

    }

    private static void startClient(String uuid) {
       new Thread(() -> {
           try {
               TimeUnit.SECONDS.sleep(new Random().nextInt(10)+1);
           } catch (InterruptedException e) {
           }
           //netty基本操作，线程组
           EventLoopGroup group = new NioEventLoopGroup();
           //netty基本操作，启动类
           Bootstrap boot = new Bootstrap();
           boot.option(ChannelOption.SO_KEEPALIVE, true)
                   .option(ChannelOption.TCP_NODELAY, true)
                   .group(group)
                   .handler(new LoggingHandler(LogLevel.INFO))
                   .channel(NioSocketChannel.class)
                   .handler(new ChannelInitializer<SocketChannel>() {
                       protected void initChannel(SocketChannel socketChannel) throws Exception {
                           ChannelPipeline pipeline = socketChannel.pipeline();
                           pipeline.addLast("http-codec",new HttpClientCodec());
                           pipeline.addLast("aggregator",new HttpObjectAggregator(1024*1024*10));
                           pipeline.addLast("hookedHandler", new WebSocketClientHandler());
                       }
                   });
           //websocke连接的地址，/pillar是因为在服务端的websockethandler设置的
           URI websocketURI = null;
           try {
               websocketURI = new URI("ws://localhost:9999/pillar");
           } catch (URISyntaxException e) {
           }
           HttpHeaders httpHeaders = new DefaultHttpHeaders();
           //进行握手
           WebSocketClientHandshaker handshaker = WebSocketClientHandshakerFactory.newHandshaker(websocketURI, WebSocketVersion.V13, null, true, httpHeaders);
           //客户端与服务端连接的通道，final修饰表示只会有一个
           Channel channel = null;
           try {
               channel = boot.connect(websocketURI.getHost(), websocketURI.getPort()).sync().channel();
           } catch (InterruptedException e) {
           }
           WebSocketClientHandler handler = (WebSocketClientHandler) channel.pipeline().get("hookedHandler");
           handler.setHandshaker(handshaker);
           handshaker.handshake(channel);
           //阻塞等待是否握手成功
           try {
               handler.handshakeFuture().sync();
           } catch (InterruptedException e) {
           }
           System.out.println("握手成功");
           //给服务端发送的内容，如果客户端与服务端连接成功后，可以多次掉用这个方法发送消息
           sengMessage(channel,uuid);
       }).start();
    }

    public static void sengMessage(Channel channel, String uuid){
        //发送的内容，是一个文本格式的内容
        String putMessage="{\"cmd\":\"0x90\",\"version\":\"v1.0\",\"uuid\":\""+uuid+"\",\"data\":null}";
        TextWebSocketFrame frame = new TextWebSocketFrame(putMessage);
        channel.writeAndFlush(frame).addListener((ChannelFutureListener) channelFuture -> {
            if (channelFuture.isSuccess()) {
                System.out.println("消息发送成功，发送的消息是："+putMessage);
            } else {
                System.out.println("消息发送失败 " + channelFuture.cause().getMessage());
            }
        });
    }

}
